﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace SharpSoft.WPF.Controls
{
    public static class val
    {
        public static readonly ControlTemplate errorTemplate;
        static val()
        {
            ResourceDictionary resDictionary = new ResourceDictionary();
            resDictionary.Source = new Uri("SharpSoft.WPF;component/Themes/Generic.xaml", UriKind.Relative);
            errorTemplate = (ControlTemplate)resDictionary["validErrorTextBoxTemplate"];
        }



        public static Range Getrange(DependencyObject obj)
        {
            return (Range)obj.GetValue(rangeProperty);
        }

        public static void Setrange(DependencyObject obj, Range value)
        {
            obj.SetValue(rangeProperty, value);
        }

        public static readonly DependencyProperty rangeProperty =
            DependencyProperty.RegisterAttached("range", typeof(Range), typeof(val), new PropertyMetadata(null));



        public static string Getregex(DependencyObject obj)
        {
            return (string)obj.GetValue(regexProperty);
        }

        public static void Setregex(DependencyObject obj, string value)
        {
            obj.SetValue(regexProperty, value);
        }

        public static readonly DependencyProperty regexProperty =
            DependencyProperty.RegisterAttached("regex", typeof(string), typeof(val), new PropertyMetadata(null));



        public static bool Getrequired(DependencyObject obj)
        {
            return (bool)obj.GetValue(requiredProperty);
        }

        public static void Setrequired(DependencyObject obj, bool value)
        {
            obj.SetValue(requiredProperty, value);
        }

        public static readonly DependencyProperty requiredProperty =
            DependencyProperty.RegisterAttached("required", typeof(bool), typeof(val), new PropertyMetadata(false));



        public static string Getlength(DependencyObject obj)
        {
            return (string)obj.GetValue(lengthProperty);
        }

        public static void Setlength(DependencyObject obj, string value)
        {
            obj.SetValue(lengthProperty, value);
        }

        public static readonly DependencyProperty lengthProperty =
            DependencyProperty.RegisterAttached("length", typeof(string), typeof(val), new PropertyMetadata(""));

        public static Binding Getbind(DependencyObject obj)
        {
            return (Binding)obj.GetValue(bindProperty);
        }

        public static void Setbind(DependencyObject obj, Binding value)
        {
            obj.SetValue(bindProperty, value);
        }

        public static readonly DependencyProperty bindProperty =
            DependencyProperty.RegisterAttached("bind", typeof(Binding), typeof(val), new PropertyMetadata(null));



        public static PropertyPath Getbindpath(DependencyObject obj)
        {
            return (PropertyPath)obj.GetValue(bindpathProperty);
        }

        public static void Setbindpath(DependencyObject obj, string value)
        {
            obj.SetValue(bindpathProperty, value);
        }

        public static readonly DependencyProperty bindpathProperty =
            DependencyProperty.RegisterAttached("bindpath", typeof(PropertyPath), typeof(val), new PropertyMetadata(null));


        public static DependencyProperty Getbindprop(DependencyObject obj)
        {
            var dp = (DependencyProperty)obj.GetValue(bindpropProperty);
            if (dp == null)
            {
                if (obj is TextBox textBox)
                {
                    dp = TextBox.TextProperty;
                }
                else if (obj is PasswordBox passwordBox)
                {
                    throw new Exception("不要再PasswordBox上设置验证绑定。");
                }
                else if (obj is ComboBox comboBox)
                {
                    dp = ComboBox.SelectedValueProperty;
                }
                else if (obj is CheckBox checkBox)
                {
                    dp = CheckBox.IsCheckedProperty;
                }
                else
                {
                    throw new Exception($"无法识别控件[{obj.GetType().FullName}]的默认绑定属性，请手动指定。");
                }
            }
            return dp;
        }

        public static void Setbindprop(DependencyObject obj, DependencyProperty value)
        {
            obj.SetValue(bindpropProperty, value);
        }

        public static readonly DependencyProperty bindpropProperty =
            DependencyProperty.RegisterAttached("bindprop", typeof(DependencyProperty), typeof(val), new PropertyMetadata(null));


        public static readonly RoutedEvent customvalEvent =
            EventManager.RegisterRoutedEvent("customval", RoutingStrategy.Bubble, typeof(EventHandler<customRoutedEventArgs>), typeof(val));

        public static void AddcustomvalHandler(DependencyObject d, EventHandler<customRoutedEventArgs> handler)
        {
            RoutedEvent routedEvent = customvalEvent;
            if (d == null)
            {
                throw new ArgumentNullException("d");
            }
            UIElement uIElement = d as UIElement;
            if (uIElement != null)
            {
                uIElement.AddHandler(routedEvent, handler);
                return;
            }
            ContentElement contentElement = d as ContentElement;
            if (contentElement != null)
            {
                contentElement.AddHandler(routedEvent, handler);
                return;
            }
            UIElement3D uIElement3D = d as UIElement3D;
            if (uIElement3D != null)
            {
                uIElement3D.AddHandler(routedEvent, handler);
                return;
            }
            throw new ArgumentException("Invalid_IInputElement");
        }
        public static void RemovecustomvalHandler(DependencyObject d, EventHandler<customRoutedEventArgs> handler)
        {
            RoutedEvent routedEvent = customvalEvent;
            if (d == null)
            {
                throw new ArgumentNullException("d");
            }
            UIElement uIElement = d as UIElement;
            if (uIElement != null)
            {
                uIElement.RemoveHandler(routedEvent, handler);
                return;
            }
            ContentElement contentElement = d as ContentElement;
            if (contentElement != null)
            {
                contentElement.RemoveHandler(routedEvent, handler);
                return;
            }
            UIElement3D uIElement3D = d as UIElement3D;
            if (uIElement3D != null)
            {
                uIElement3D.RemoveHandler(routedEvent, handler);
                return;
            }
            throw new ArgumentException("Invalid_IInputElement");
        }

        private static void EnumVisual(Visual visual, ref List<Visual> ctrls)
        {
            if (Getbindpath(visual) != null || Getbind(visual) != null)
            {
                ctrls.Add(visual);
            }
            if (visual is ContentControl cc && cc.Content is Visual vis)
            {
                EnumVisual(vis, ref ctrls);
                return;
            }
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
            {
                Visual childVisual = (Visual)VisualTreeHelper.GetChild(visual, i);
                if (childVisual != null)
                {
                    EnumVisual(childVisual, ref ctrls);
                }
            }
        }
        public static IValueConverter GetBindConverter(DependencyObject obj)
        {
            return (IValueConverter)obj.GetValue(BindConverterProperty);
        }

        public static void SetBindConverter(DependencyObject obj, IValueConverter value)
        {
            obj.SetValue(BindConverterProperty, value);
        }
        /// <summary>
        /// 可以为绑定制定一个值转换器
        /// </summary>
        public static readonly DependencyProperty BindConverterProperty =
            DependencyProperty.RegisterAttached("BindConverter", typeof(IValueConverter), typeof(val), new PropertyMetadata(null));



        private static List<BindingExpressionBase> Getbindlist(DependencyObject obj)
        {
            return (List<BindingExpressionBase>)obj.GetValue(bindlistProperty);
        }

        private static void Setbindlist(DependencyObject obj, List<BindingExpressionBase> value)
        {
            obj.SetValue(bindlistProperty, value);
        }

        // Using a DependencyProperty as the backing store for bindlist.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty bindlistProperty =
            DependencyProperty.RegisterAttached("bindlist", typeof(List<BindingExpressionBase>), typeof(val), new PropertyMetadata(null));




        /// <summary>
        /// 将验证规则应用到指定的容器控件中的所有输入控件
        /// </summary>
        /// <param name="usejsonDefaultTypeConverter">是否为每一个绑定都附加默认得Json.NET值转换器（优先使用TypeConverter指定的转换器）</param>
        public static List<BindingExpressionBase> Apply(Panel panel, bool usejsonDefaultTypeConverter = true)
        {
            List<BindingExpressionBase> bindexps = new List<BindingExpressionBase>();

            List<Visual> ctrls = new List<Visual>();
            EnumVisual(panel, ref ctrls);
            foreach (var editctrl in ctrls)
            {
                Binding binding = Getbind(editctrl);
                PropertyPath pp = Getbindpath(editctrl);
                if (binding != null)
                {
                    binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                    binding.ValidatesOnDataErrors = true;
                    binding.NotifyOnValidationError = true;
                }
                else if (pp != null)
                {//有设置验证绑定路径
                    //var type = editctrl.GetType();//获取输入控件的类型
                    //{//有找到指定的验证目标依赖属性。 
                    binding = new Binding()
                    {
                        Path = pp,
                        Mode = BindingMode.TwoWay,
                        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                        ValidatesOnDataErrors = true,
                        NotifyOnValidationError = true
                    };
                }
                else
                {
                    continue;
                }
                var valtarget = Getbindprop(editctrl);
                var converter = GetBindConverter(editctrl);//获取指定的类型转换器
                if (converter != null)
                {
                    binding.Converter = converter;
                }
                else
                {
                    if (usejsonDefaultTypeConverter)
                    {
                        binding.Converter = new JTokenDefaultConverter();
                    }
                }

                System.Windows.Controls.Validation.SetErrorTemplate(editctrl, errorTemplate);
                var required = Getrequired(editctrl);
                if (required)
                {
                    binding.ValidationRules.Add(new required());
                }
                var ran = Getrange(editctrl);
                if (ran != null)
                {
                    binding.ValidationRules.Add(new range() { min = ran.Min, max = ran.Max });
                }
                var reg = Getregex(editctrl);
                if (!string.IsNullOrEmpty(reg))
                {
                    binding.ValidationRules.Add(new regex() { expression = reg });
                }
                var len = Getlength(editctrl);
                if (!string.IsNullOrEmpty(len))
                {
                    var l = len.Split(',');
                    if (l.Length != 2)
                    {
                        throw new Exception("为绑定指定的长度约束必须为\"1,9\"的形式，前面数字表示最小长度，后面数字表示最大长度，为-1表示不限制。");
                    }
                    var min = int.Parse(l[0]);
                    var max = int.Parse(l[1]);
                    binding.ValidationRules.Add(new length() { min = min, max = max });
                }
                if (editctrl is UIElement uie)
                {
                    customRoutedEventArgs E = new customRoutedEventArgs() { RoutedEvent = customvalEvent, Source = uie };
                    var cus = new custom() { uiele = uie, EventArgs = E };
                    binding.ValidationRules.Add(cus);
                }
                var bindexp = BindingOperations.SetBinding(editctrl, valtarget, binding);
                bindexps.Add(bindexp);

            }
            Setbindlist(panel, bindexps);
            return bindexps;

        }

        public static bool ValidateAll(Panel panel)
        {
            bool allval = true;
            var bindexps = Getbindlist(panel);
            if (bindexps == null)
            {
                throw new Exception("指定的容器尚未进行任何验证器操作。");
            }
            if (bindexps != null)
            {
                foreach (var item in bindexps)
                {
                    item.UpdateSource();
                    var val = item.ValidateWithoutUpdate();
                    if (!val)
                    {
                        allval = false;
                    }
                }
            }
            return allval;
        }

    }


}
